
/**
 * 
 * Moises Florez and Peter Matano
 *
 */
public class OS2 implements OperatingSystem {
	private Hardware simHW;
	private int blockCounter = 1;	

	private int countdown = 3000;	
	public OS2(Hardware hw) {
		simHW = hw; // Set simulator hardware.
	}

	@Override
	public void interrupt(Hardware.Interrupt it) {
		switch (it) {
		case illegalInstruction:
			System.out.println("IlleagleInstruction");
			simHW.store(Hardware.Address.haltRegister, 2);
			break;
			
		case reboot:
			System.out.println("reboot");
			// Load the disk to primary store one block at the time.			
			simHW.store(Hardware.Address.diskBlockRegister, 0);
			simHW.store(Hardware.Address.diskAddressRegister, Hardware.Address.userBase);
			simHW.store(Hardware.Address.diskCommandRegister, Hardware.Disk.readCommand);			
			simHW.store(Hardware.Address.PCRegister, Hardware.Address.idleStart);//Set PCRegister to prevent illegal instruction interrupt
			break;
		
		case systemCall:
			System.out.println("SystemCall");
			operatingSystemCall(simHW.fetch(Hardware.Address.systemBase));
			break;
		
		case invalidAddress:
			System.out.println("invalidAddress");
			simHW.store(Hardware.Address.haltRegister, 2);
			break;
			
		case disk:
			System.out.println("disk");
			
			int programSize = simHW.fetch(Hardware.Address.userBase);//Find how many blocks first program occupies 
			int nextBlockStartaddress = simHW.fetch(Hardware.Address.diskAddressRegister) + Hardware.Disk.blockSize; //Find where to load next block
			
			if(programSize == 0) //If disk is empty then halt OS
			{
				simHW.store(Hardware.Address.haltRegister, 2);
			}			
			
			if (blockCounter <= Hardware.Disk.blockCount) // Loads all of the blocks into User Space.
			{	
				simHW.store(Hardware.Address.diskBlockRegister, blockCounter);//Next block from disk   			
				simHW.store(Hardware.Address.diskAddressRegister, nextBlockStartaddress);//Set address			
				simHW.store(Hardware.Address.diskCommandRegister, Hardware.Disk.readCommand);//Read from disk to primary storage					
				simHW.store(Hardware.Address.PCRegister, Hardware.Address.idleStart);//Set PCRegister to prevent illegal instruction interrupt
				blockCounter++;
				
			}		
			
			else
			{
				int baseRegister = Hardware.Address.userBase + Hardware.Disk.blockSize;
				int pcRegister = Hardware.Address.userBase + Hardware.Disk.blockSize;  
				int topRegister = baseRegister + (programSize + Hardware.Disk.blockSize);		
				
				this.simHW.store(Hardware.Address.PCRegister, pcRegister); // Address of the next program to execute.
				this.simHW.store(Hardware.Address.baseRegister, baseRegister); // Lowest legal address accessible to the current running process.
				this.simHW.store(Hardware.Address.topRegister, topRegister); // One more than the highest legal address.
			}
			
			
			break;
			
		case countdown:
			System.out.println("countDown");
			int cDownReg = simHW.fetch(Hardware.Address.countdownRegister);
			if (cDownReg == 0) { // Count down finished reset to stop it from hanging.
				this.simHW.store(Hardware.Address.countdownRegister, countdown); // set a new count down to keep system from hanging.
				simHW.store(Hardware.Address.PCRegister, Hardware.Address.idleStart);//Set PCRegister to prevent illegal instruction interrupt
			}
						
			break;
		}
	}

	public void operatingSystemCall(int sysCall) {
		int indexAddress;
		int indexBlock;		
		switch (sysCall) {
		case SystemCall.exec:
			System.out.println("exec");
						
			indexAddress = simHW.fetch(1); 
			indexBlock = simHW.fetch(indexAddress);
			
			if(indexBlock > 0)
			{	
				
				int baseRegister = indexBlock + Hardware.Disk.blockSize;
				int pcRegister = indexBlock + Hardware.Disk.blockSize;  
				int topRegister = baseRegister + (indexBlock + 32);
				
				System.out.println("indexAddress:" + indexAddress);
				System.out.println("indexBlock:" + indexBlock);
				
				
				System.out.println("baseRegister:" + baseRegister);
				System.out.println("pcRegister:" + pcRegister);
				System.out.println("topRegister:" + topRegister);
				
				
				this.simHW.store(Hardware.Address.PCRegister, pcRegister); // Address of the next program to execute.
				this.simHW.store(Hardware.Address.baseRegister, baseRegister); // Lowest legal address accessible to the current running process.
				this.simHW.store(Hardware.Address.topRegister, topRegister); // One more than the highest legal address.
			}
			
			
			break;
		case SystemCall.exit:
			System.out.println("exit");
			simHW.store(Hardware.Address.haltRegister, 2);
			break;
		
		case SystemCall.getSlot:
			System.out.println("getSlot");
			indexAddress =  this.simHW.fetch(1); // Get register 1.
			indexBlock = this.simHW.fetch(indexAddress);
			
			this.simHW.store(1, indexAddress);
			this.simHW.store(2, indexBlock);
			this.simHW.store(0, Hardware.Status.ok);
			
			break;
		
		case SystemCall.putSlot:
			System.out.println("putSlot");
			this.simHW.store(0, Hardware.Status.ok);	
			break;
		
		case SystemCall.yield:
			System.out.println("yiled");
			this.simHW.store(0, Hardware.Status.ok);
			
		}
	}
	
			
		
}